package com.king.juc.atomicdemo.aba;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

import static com.king.juc.utils.ThreadUtil.sleep;

/**
 * ABA 问题
 *      主线程感知不到别的线程是否修改过该变量
 * @author king
 * @date 2020/11/30 23:51
 */
@Slf4j(topic = "c.AbaDemo")
public class AbaDemo {

    static AtomicReference<String> ref = new AtomicReference<>("A");
    static AtomicStampedReference<String> asr = new AtomicStampedReference<>("A", 0);

    public static void main(String[] args) {
        log.debug("main start....");

        // 获取值A
        String prev = ref.get();
        String reference = asr.getReference();

        // 获取版本号
        int stamp = asr.getStamp();
        log.debug("版本号: {}", stamp);

        // 模拟其他线程修改
        other();

        sleep(1);

        // 尝试改为C
        log.debug("change A->C {}", ref.compareAndSet(prev, "C"));
        log.debug("Stamped change A->C {}", asr.compareAndSet(reference, "C", stamp, stamp + 1));
    }

    private static void other() {
        log.debug("change A->B {}", ref.compareAndSet(ref.get(), "B"));

        int stamp = asr.getStamp();
        log.debug("版本号: {}", stamp);
        log.debug("Stamped change A->B {}", asr.compareAndSet(asr.getReference(), "B", stamp, stamp + 1));

        log.debug("change B->A {}", ref.compareAndSet(ref.get(), "A"));

        stamp = asr.getStamp();
        log.debug("版本号: {}", stamp);
        log.debug("Stamped change B->A {}", asr.compareAndSet(asr.getReference(), "B", stamp, stamp + 1));
    }
}
